package org.jlamp.server;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import org.jlamp.core.util.JlampUtils;
import org.reflections.Reflections;

import java.io.PrintStream;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 请求处理器
 *
 * @author zhangcs
 * @since 1.0
 */
public class JlampServerHandler extends SimpleChannelInboundHandler<Object> {

    private static final PrintStream LOGGER = JlampUtils.logger();

    private static final Map<String, JlampPoint> HANDLER_MAP = new ConcurrentHashMap<>(16);

    static {
        Reflections reflections = new Reflections("org.jlamp.server");
        Set<Class<? extends JlampPoint>> classes = reflections.getSubTypesOf(JlampPoint.class);
        classes.forEach(klass -> {
            try {
                JlampPoint point = klass.newInstance();
                String key = point.url().toUpperCase(Locale.ROOT);
                HANDLER_MAP.put(key, point);
            } catch (Exception e) {
                e.printStackTrace(LOGGER);
            } finally {
                LOGGER.println("Binding URI Handler:" + String.join("\n\t", HANDLER_MAP.keySet()));
            }
        });
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // 记录日志
        cause.printStackTrace(LOGGER);
        // 关闭连接
        ctx.close();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object request) {
        if (!(request instanceof HttpRequest)) {
            ctx.fireChannelRead(request);
            return;
        }

        try {
            handle(ctx, (HttpRequest) request);
        } catch (Exception e) {
            e.printStackTrace(LOGGER);
            // 异常，返回500
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR);
            ctx.writeAndFlush(response);
        }
    }

    private void handle(ChannelHandlerContext ctx, HttpRequest request) {
        String uri = request.uri().toUpperCase(Locale.ROOT);
        String separator = "/";
        if (uri.startsWith(separator)) {
            uri = uri.substring(1);
        }

        JlampPoint point = HANDLER_MAP.get(uri);
        if (point == null) {
            // 404
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND);
            ctx.writeAndFlush(response);
            return;
        }

        // 数据
        String data = point.read();
        ByteBuf byteBuf = Unpooled.copiedBuffer(data, CharsetUtil.UTF_8);

        // 封装响应对象
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);
        HttpHeaders headers = response.headers();
        headers.set(HttpHeaderNames.CONTENT_TYPE, "text/plain;charset=UTF-8");

        // 写响应
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }

}
